#include "ArithmeticEncoder.h"
#include <string.h>

ArithmeticEncoder::ArithmeticEncoder(ProbabilityModel* model)
{
	this->model = model;
	lowerBound = 0;
	upperBound = 0xFFFF;
	underflow = 0;
}


ArithmeticEncoder::~ArithmeticEncoder(void)
{
}


BitBuffer ArithmeticEncoder::encodeString(const char* string)
{
	BitBuffer buffer(1024);

	for (int i = 0; i < strlen(string); ++i)
	{
		encodeSymbol(string[i], buffer);
	}
	return buffer;
}

void ArithmeticEncoder::encodeSymbol(unsigned char symbol, BitBuffer& buffer)
{
	int range = upperBound - lowerBound + 1;
	upperBound = lowerBound + (range * model->getUpperBoundForSymbol(symbol)) / model->getAllSymbolsCount() - 1;
	lowerBound = lowerBound + (range * model->getLowerBoundForSymbol(symbol)) / model->getAllSymbolsCount();

	while(true)
    {
        if ((upperBound & 0x8000) == (lowerBound & 0x8000))
        {
            buffer.appendBit(upperBound & 0x8000);
            while (underflow > 0)
            {
                buffer.appendBit(~upperBound & 0x8000);
                --underflow;
            }
        }
        else if ((lowerBound & 0x4000) && !(upperBound & 0x4000))
        {
            ++underflow;
            lowerBound &= 0x3fff;
            upperBound |= 0x4000;
        }
        else
            return;
        lowerBound <<= 1;
        upperBound <<= 1;
        upperBound |= 1;
    }
}